/*******************************************************************************
* @file     usb task
* @version  V1.00
*******************************************************************************/
#include "bsp.h"
#include "bsp_api.h"
#include "os_obj.h"
#include "sys_task.h"
#include "bsp_xmc_nand.h"
#include "str_ext.h"

/*****************************************************************************
* @brief   const 
*****************************************************************************/

/*****************************************************************************
* @brief   function
*****************************************************************************/
void nand_app_init(void);
void nand_opt(void);
void nand_flash_opt(void);
void nor_flash_task(const void *argument);

/*****************************************************************************
* @brief   extern var
*****************************************************************************/

/*****************************************************************************
* @brief   loacal var
*****************************************************************************/
uu32 nand_buff[1024 + 32];

/*****************************************************************************
* @brief   nand_task.
* @param   argument
* @return  none
*****************************************************************************/
void nand_task(void *argument)
{
	osDelay(2000);

	nand_app_init();

	//nand_flash_test();

	while (1)
	{
		osDelay(100);
		nand_opt();
		nor_flash_task(argument);
		nand_flash_opt();
	}
}

void nand_app_init(void)
{
	nand_id_type nid;
	nand_init();

#if 1
	nand_read_id(&nid);
	dbg_print("nand mid: %02X, nand did: %08X \n", nid.maker_id, nid.id);

#endif
}

void nand_opt(void)
{
	uu32 page;
	uu32 tick;

	// 读取测试
	if (Gst.fmc.nand_read_req && (!Gst.fmc.opt_with_ecc))
	{
		uu32 size = Gst.fmc.nand_read_req * atio_nand.page_mainsize;
		uu32 page_offset = 0;

		tick = app_tick_get();
		while (Gst.fmc.nand_read_req)
		{
			Gst.fmc.exe_st = nand_read_page((u8 *)nand_buff, Gst.fmc.nand_page + page_offset, 0, atio_nand.page_mainsize);
			page_offset++;
			Gst.fmc.nand_read_req--;
		}

		dbg_print("nand read size: %dMB time %d\n", size / 1024 / 1024, app_tick_get() - tick);
	}

	// 读取测试 + ECC
	if (Gst.fmc.nand_read_req && Gst.fmc.opt_with_ecc)
	{
		uu32 size = Gst.fmc.nand_read_req * atio_nand.page_mainsize;
		uu32 page_offset = 0;

		tick = app_tick_get();
		while (Gst.fmc.nand_read_req)
		{
			Gst.fmc.exe_st = nand_read_page((u8 *)nand_buff, Gst.fmc.nand_page + page_offset, 0, 0);
			Gst.fmc.nand_read_req--;
			page_offset ++;
		}

		dbg_print("nand read size: %dMB time %d\n", size / 1024 / 1024, app_tick_get() - tick);
	}

	// 块写测试
	if (Gst.fmc.nand_write_req && (!Gst.fmc.opt_with_ecc))
	{
		Gst.fmc.nand_write_req = 0;
		Gst.fmc.exe_st = nand_erase_block(Gst.fmc.nand_page / atio_nand.block_pagenum);
		Gst.fmc.nand_page /= atio_nand.block_pagenum;
		Gst.fmc.nand_page *= atio_nand.block_pagenum;
		for (page = 0; page < atio_nand.block_pagenum; page++)
		{
			loop(atio_nand.page_mainsize / 4)
			{
				nand_buff[index] = index + page * atio_nand.page_mainsize / 4 + 5;
			}

			Gst.fmc.exe_st = nand_write_page((void *)nand_buff, Gst.fmc.nand_page + page, 0, atio_nand.page_mainsize);
		}
	}

	// 块写测试 + ECC
	if (Gst.fmc.nand_write_req && Gst.fmc.opt_with_ecc)
	{
		Gst.fmc.nand_write_req = 0;

		Gst.fmc.exe_st = nand_erase_block(Gst.fmc.nand_page / atio_nand.block_pagenum);
		Gst.fmc.exe_st = nand_erase_block(Gst.fmc.nand_page / atio_nand.block_pagenum + 1);

		Gst.fmc.nand_page /= atio_nand.block_pagenum;
		Gst.fmc.nand_page *= atio_nand.block_pagenum;
		for (page = 0; page < atio_nand.block_pagenum; page++)
		{
			loop(atio_nand.page_mainsize / 4)
			{
				nand_buff[index] = index + page * atio_nand.page_mainsize / 4 + 5;
			}
			
			// ECC 校验写
			Gst.fmc.exe_st = nand_write_page((void *)nand_buff, Gst.fmc.nand_page + page + atio_nand.block_pagenum, 0, 0);

			// 修改一位, 合并ECC
			((uu8*)nand_buff)[page] ^= 1UL<<(page & 0x7);
			if(page == 5)
				((uu8*)nand_buff)[128] ^= 1UL<<2;	
			copy_u32(atio_nand.ecc_hdbuf, &nand_buff[(atio_nand.page_mainsize >> 2) + 4], 8);
			
			// 连同ECC值写入测试页
			Gst.fmc.exe_st = nand_write_page((void *)nand_buff, Gst.fmc.nand_page + page, 0, atio_nand.page_mainsize + 48);
		}

		Gst.fmc.nand_read_req = 64;
	}

	// 页写测试
	if (Gst.fmc.nand_write_req == 2)
	{
		int blk = 2;

		Gst.fmc.nand_write_req = 0;

		dbg_print("earse block %d\n", blk);
		nand_erase_block(blk);

		loop(8)
			nand_buff[index] = index;

		dbg_puts("write page cell 0\n");
		nand_write_page((void *)nand_buff, atio_nand.block_pagenum * blk, 0, 32);
		dbg_puts("write page cell 64\n");
		nand_write_page((void *)nand_buff, atio_nand.block_pagenum * blk, 64, 32);
		dbg_puts("write page cell 128\n");
		nand_write_page((void *)nand_buff, atio_nand.block_pagenum * blk, 128, 32);
		dbg_puts("write page cell 2048\n");
		nand_write_page((void *)nand_buff, atio_nand.block_pagenum * blk, 2048, 32);
		dbg_puts("write page cell 2048 + 32\n");
		nand_write_page((void *)nand_buff, atio_nand.block_pagenum * blk, 2048 + 32, 32);

		set_u32(nand_buff, 0, sizeof(nand_buff) >> 2);

		dbg_puts("read back\n");
		nand_read_page((void *)nand_buff, atio_nand.block_pagenum * blk, 0, 256);
		dbg_u32_print("main data:\n", nand_buff, 256 / 4, 16);
		nand_read_page((void *)nand_buff, atio_nand.block_pagenum * blk, 2048, 64);

		dbg_u32_print("spare data:\n", nand_buff, 64 / 4, 20);
	}

	if (Gst.fmc.nand_cpage_rw_req)
	{
		int blk = 512;
		uint8_t fmc_nand_read_page(uint32_t page_addr);
		uint8_t fmc_nand_read_cache(uint16_t cell, uint8_t * dat, uint16_t Len);
		uint8_t fmc_nand_write_cache(uint16_t cell, const uint8_t *dat, uint16_t Len);
		uint8_t fmc_nand_program_exe(uint32_t page_addr);
		char nand_fmc_dev_link(void);

		nand_fmc_dev_link();
		Gst.fmc.nand_cpage_rw_req = 0;

		// ²Á³ý
		dbg_print("earse block %d\n", blk);
		nand_erase_block(blk);

		loop(516)
			nand_buff[index] = index;

		// Ð´Èë
		fmc_nand_write_cache(0, (void *)nand_buff, 2048 + 16);
		fmc_nand_program_exe(atio_nand.block_pagenum * blk);

		set_u32(nand_buff, 0, sizeof(nand_buff) >> 2);
		fmc_nand_write_cache(0, (void *)nand_buff, 2048 + 16);

		dbg_puts("read back\n");
		fmc_nand_read_page(atio_nand.block_pagenum * blk);
		fmc_nand_read_cache(0, (void *)nand_buff, 2048 + 16);

		dbg_u32_print("data:\n", nand_buff, 512 + 4, 16);
	}
}
